#include "album_burst.h"
#include "file_utils.h"
#include "elog.h"
#include "elog_file.h"
#include "album_common.h"
#include "img_utils.h"

#include <stdlib.h>

#include <string>
#include <filesystem>

namespace fs = std::filesystem;

static sqlite3* m_db = nullptr;
static std::string burst_table_name = "burstInfo";
static std::string burst_folder_path = album_path + burst_path;


AlbumBurst::AlbumBurst() {

}

AlbumBurst::~AlbumBurst() {

}

int AlbumBurst::createBurstInfoTable(sqlite3* db) {
    char* errMsg = 0;
    int rc;

    m_db = db;

    // 创建burstInfo表（如果还未创建）
    const char* createTableSQL = R"(
        CREATE TABLE IF NOT EXISTS burstInfo (
            id INTEGER PRIMARY KEY,
            file_path TEXT UNIQUE,
            modification_time INTEGER,
            file_count INTEGER,
            thumbnail_path TEXT,
            width TEXT,
            height TEXT,
            file_size INTEGER,
            media_type INTEGER
        );
    )";

    rc = sqlite3_exec(db, createTableSQL, NULL, 0, &errMsg);
    if (rc != SQLITE_OK) {
        log_e("cannot create table: %s", errMsg);
        sqlite3_free(errMsg);
    } else {
        log_i("create table successfully");
    }

    return 0;
    
}

int AlbumBurst::insertBurstInfo(const BurstInfo& burst_info) {
    log_i("insertBurstInfo file_path = %s", burst_info.common_info.file_path.c_str());
    if (!m_db) {
        log_e("The database connection is not initialized");
        return -1;
    }

    std::string insertDataSQL = "INSERT INTO " + burst_table_name + " (file_path, modification_time, file_count, thumbnail_path, width, height, file_size, media_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?);";

    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(m_db, insertDataSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, burst_info.common_info.file_path.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int64(stmt, 2, burst_info.common_info.modification_time);
    sqlite3_bind_int(stmt, 3, burst_info.unique_info.file_count);
    sqlite3_bind_text(stmt, 4, burst_info.common_info.thumbnail_path.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 5, burst_info.common_info.width);
    sqlite3_bind_int(stmt, 6, burst_info.common_info.height);
    sqlite3_bind_int64(stmt, 7, burst_info.common_info.file_size);
    sqlite3_bind_int(stmt, 8, burst_info.common_info.media_type);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not insert :%s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return -1;
    }

    sqlite3_finalize(stmt);

    return 0;
}

int AlbumBurst::getCount() {
    int count = 0;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return count;
    }

    std::string sql = "SELECT COUNT(*) FROM " + burst_table_name + ";";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return count;
    }

    if (sqlite3_step(stmt) == SQLITE_ROW) {
        count = sqlite3_column_int(stmt, 0);
    }

    sqlite3_finalize(stmt);

    return count;
}

std::vector<BurstInfo> AlbumBurst::queryBurstInfoByTime() {
    std::vector<BurstInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + burst_table_name + " ORDER BY modification_time DESC;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        BurstInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.unique_info.file_count = sqlite3_column_int(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.file_size = sqlite3_column_int(stmt, 7);
        info.common_info.media_type = sqlite3_column_int(stmt, 8);

        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

std::vector<BurstInfo> AlbumBurst::queryBurstInfoByTime(int page_index, int page_size) {
    std::vector<BurstInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + burst_table_name + " ORDER BY modification_time DESC LIMIT ? OFFSET ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    int offset = page_index * page_size;
    sqlite3_bind_int(stmt, 1, page_size);
    sqlite3_bind_int(stmt, 2, offset);

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        BurstInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.unique_info.file_count = sqlite3_column_int(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.file_size = sqlite3_column_int(stmt, 7);
        info.common_info.media_type = sqlite3_column_int(stmt, 8);

        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}
    
std::vector<BurstInfo> AlbumBurst::queryAllBurstInfo() {
    std::vector<BurstInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + burst_table_name + ";";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        BurstInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.unique_info.file_count = sqlite3_column_int(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.file_size = sqlite3_column_int(stmt, 7);
        info.common_info.media_type = sqlite3_column_int(stmt, 8);

        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

std::vector<BurstInfo> AlbumBurst::queryBurstInfoByFilepath(const std::string& file_path) {
    std::vector<BurstInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + burst_table_name + " WHERE file_path = ?";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    sqlite3_bind_text(stmt, 1, file_path.c_str(), -1, SQLITE_STATIC);

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        BurstInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.unique_info.file_count = sqlite3_column_int(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.file_size = sqlite3_column_int(stmt, 7);
        info.common_info.media_type = sqlite3_column_int(stmt, 8);

        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

bool AlbumBurst::updateBurstInfo(const std::string& file_path, const std::string& new_filename) {
    if (!m_db) {
        log_e("The database connection is not initialized");
        return false;
    }

    std::string sql = "UPDATE " + burst_table_name + " SET file_path = ? WHERE file_path = ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, new_filename.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, file_path.c_str(), -1, SQLITE_STATIC);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not update: %s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);

    return true;
}
    
bool AlbumBurst::deleteBurstInfo(const std::string& file_path) {
    log_i("deleteBurstInfo file_path = %s", file_path.c_str());

    if (!m_db) {
        log_e("The database connection is not initialized");
        return false;
    }

    std::string sql = "DELETE FROM " + burst_table_name + " WHERE file_path = ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, file_path.c_str(), -1, SQLITE_STATIC);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not delete: %s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    
    return true;
}
    
void AlbumBurst::printBurstInfo(const BurstInfo& burst_info) {
    log_i("burst_info file_path = %s", burst_info.common_info.file_path.c_str());
    log_i("burst_info modification_time = %ld", burst_info.common_info.modification_time);
    log_i("burst_info file_count = %d", burst_info.unique_info.file_count);
    log_i("burst_info file_size = %d", burst_info.common_info.file_size);
}

bool AlbumBurst::deleteDirectory(const std::string& burst_dir) {
    std::string delete_burst_dir = extractFolderPath(burst_dir, 1);
    log_i("deleteDirectory delete_burst_dir = %s", delete_burst_dir.c_str());
    if (delete_burst_dir != "" && isPathContains(delete_burst_dir, burst_folder_path) && delete_burst_dir.size() > burst_folder_path.size()) {
        if (deleteBurstInfo(burst_dir)) {
            deleteFolder(delete_burst_dir);
            return true;
        } else {
            return false;
        }
    }

    return false;
}

bool AlbumBurst::renameDirectory(const std::string& burst_dir_path, const std::string& new_burst_name) {
    if (burst_dir_path != "" && isPathContains(burst_dir_path, burst_folder_path) && burst_dir_path.size() > burst_folder_path.size()) {
        std::string new_burst_path = burst_folder_path + new_burst_name;
        if (renameFile(burst_dir_path, new_burst_path)) {
            updateBurstInfo(burst_dir_path, new_burst_path);
            return true;
        } else {
            return false;
        }
    }

    return false;
}

bool AlbumBurst::updateBurst(const std::string& burst_dir_path) {
    log_i("updateBurst folder_path = %s", burst_dir_path.c_str());
    if (burst_dir_path != "" && isPathContains(burst_dir_path, burst_folder_path) && burst_dir_path.size() > burst_folder_path.size()) {
        BurstInfo info;
        info.common_info.modification_time = getFileModifiedTime(burst_dir_path);
        info.unique_info.file_count = countFilesWithExtension(burst_dir_path, ".jpg");
        info.common_info.media_type = MEDIA_BURST;
        info.common_info.file_size = getTotalSizeOfFilesWithExtension(burst_dir_path, ".jpg");

        std::string first_file_path = burst_dir_path + "/" + "1.jpg";
        if (!fs::exists(first_file_path))
            first_file_path = burst_dir_path + "/" + "1.jpeg";
        log_i("first file path = %s", first_file_path.c_str());
        std::string dest_thumbnail_path;
        if (fs::exists(first_file_path)) {
            dest_thumbnail_path = burst_dir_path + "/burst_thumbnail.jpg";
            if (getImageSize(dest_thumbnail_path).width < album_thumbnail_width) {
                imageDownsample(first_file_path, dest_thumbnail_path, album_thumbnail_width, album_thumbnail_height);
            }
            std::vector<BurstInfo> burst_info_list = queryBurstInfoByFilepath(first_file_path);
            if (!burst_info_list.empty())
                return -1;
            info.common_info.file_path = first_file_path;
            // imageDownsample(first_file_path, dest_thumbnail_path, album_thumbnail_width, album_thumbnail_height);
        }
        
        if (fs::exists(dest_thumbnail_path)) {
            info.common_info.thumbnail_path = dest_thumbnail_path;
            insertBurstInfo(info);
            fileSync();
        
            return true;
        } 
    }

    return false;
}